#include "ModelSlicesProducer.h"

QVector<QPair<QPair<float, float>, Edge>> ModelSlicesProducer::preprocessModelDataAlongDirection(const QVector<Edge> &model_edges, const QVector3D &direction_norm)
{
    // 存储预处理后的边分区
    QVector<QPair<QPair<float, float>, Edge>> prepreprocess_edges_partitions;

    // 遍历所有边，计算投影区间
    for (const Edge& edge : model_edges)
    {
        // 计算两个顶点在方向向量上的投影值
        float a = QVector3D::dotProduct(edge.v1.pos, direction_norm);
        float b = QVector3D::dotProduct(edge.v2.pos, direction_norm);

        // 更新最高点和最低点的模长
        m_highest = std::max(m_highest, std::max(a, b));
        m_lowest = std::min(m_lowest, std::min(a, b));

        // a_i 取模型顶点，对应区间左端点
        QPair<float, float> partition = (a > b) ? QPair<float, float>(a, b) : QPair<float, float>(b, a);

        // 将区间和边存储到结果中
        prepreprocess_edges_partitions.append(qMakePair(partition, edge));
    }

    // 对区间进行排序：先按 a_i 降序排序，再按 b_i 降序排序
    std::sort(prepreprocess_edges_partitions.begin(), prepreprocess_edges_partitions.end(),
              [](const QPair<QPair<float, float>, Edge>& p1, const QPair<QPair<float, float>, Edge>& p2) {
                  // 比较 a_i
                  if (p1.first.first != p2.first.first) {
                      return p1.first.first > p2.first.first;
                  }
                  // 如果 a_i 相等，比较 b_i
                  return p1.first.second > p2.first.second;
              });

    return prepreprocess_edges_partitions;
}

int calculateInsertCount(int edge_count)
{
    // 简单的线性映射：每5条边插入1个切片，最多3个
    if (edge_count <= 2) return 0;
    // return std::min((edge_count + 2) / 5, 3);
    return std::min(static_cast<int>(std::log(edge_count + 1)), 5);
}

void insertSlicesBasedOnCounts(QVector<float>& strides, const QVector<int>& insert_counts, float min_stride)
{
    QVector<float> new_strides;
    const float min_spacing = min_stride * 0.5f; // 容差 = 间隔的0.1倍

    for (int i = 0; i < strides.size() - 1; ++i) {
        new_strides.append(strides[i]);

        int count = insert_counts[i];
        if (count > 0) {
            qDebug() << "插入" << count;
            float interval_start = strides[i+1];
            float interval_end = strides[i];
            float interval_length = interval_end - interval_start;

            // 在区间内均匀插入切片
            for (int j = 1; j <= count; ++j) {
                float ratio = static_cast<float>(j) / (count + 1);
                float new_slice = interval_start + ratio * interval_length;

                // 检查是否与现有切片太接近
                bool too_close = false;
                for (const float& existing : new_strides) {
                    if (std::fabs(new_slice - existing) < min_spacing) {
                        too_close = true;
                        break;
                    }
                }

                if (!too_close) {
                    new_strides.append(new_slice);
                }
            }
        }
    }

    new_strides.append(strides.last());

    // 排序并去重
    std::sort(new_strides.begin(), new_strides.end());
    new_strides.erase(std::unique(new_strides.begin(), new_strides.end()), new_strides.end());

    strides = new_strides;
}

#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>
#include <cmath>  // 用于浮点数精度比较

// 浮点数比较的精度阈值（可根据实际数据精度调整）
const float EPSILON = 1e-6f;

void loadAdaptiveSamplingPoints(const QString& filename,
                                QVector<float>& sampling_points,
                                QVector<qsizetype>& newly_added_points_indice)
{
    // 清空输入容器，避免残留数据
    sampling_points.clear();
    newly_added_points_indice.clear();

    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开自适应采样文件:" << filename;
        return;
    }

    QByteArray jsonData = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(jsonData);
    if (doc.isNull()) {
        qWarning() << "无效的JSON格式:" << filename;
        return;
    }

    QJsonObject rootObj = doc.object();

    // 检查是否包含adaptive_sampling对象
    if (!rootObj.contains("adaptive_sampling")) {
        qWarning() << "JSON文件中缺少 adaptive_sampling 字段";
        return;
    }
    QJsonObject samplingObj = rootObj["adaptive_sampling"].toObject();

    // --------------------------
    // 1. 读取所有采样点（原始+新增）
    // --------------------------
    if (!samplingObj.contains("all_points")) {
        qWarning() << "JSON文件中缺少 all_points 字段";
        return;
    }
    QJsonObject allPointsObj = samplingObj["all_points"].toObject();

    if (!allPointsObj.contains("x_position")) {
        qWarning() << "JSON文件中缺少 all_points.x_position 字段";
        return;
    }
    QJsonArray allPointsArray = allPointsObj["x_position"].toArray();
    sampling_points.reserve(allPointsArray.size());
    for (const QJsonValue& value : allPointsArray) {
        sampling_points.append(static_cast<float>(value.toDouble()));
    }

    // --------------------------
    // 2. 读取新增点坐标并匹配下标
    // --------------------------
    if (!samplingObj.contains("added_points")) {
        qWarning() << "JSON文件中缺少 added_points 字段";
        return;
    }
    QJsonObject addedPointsObj = samplingObj["added_points"].toObject();

    if (!addedPointsObj.contains("x_position")) {
        qWarning() << "JSON文件中缺少 added_points.x_position 字段";
        return;
    }
    QJsonArray addedPointsArray = addedPointsObj["x_position"].toArray();
    QVector<float> addedPoints;
    addedPoints.reserve(addedPointsArray.size());
    for (const QJsonValue& value : addedPointsArray) {
        addedPoints.append(static_cast<float>(value.toDouble()));
    }

    // 遍历新增点，在总采样点中查找对应下标（考虑浮点数精度）
    for (float addedPoint : addedPoints) {
        bool found = false;
        for (qsizetype i = 0; i < sampling_points.size(); ++i) {
            // 浮点数比较：差值小于阈值则认为相等
            if (std::fabs(sampling_points[i] - addedPoint) < EPSILON) {
                newly_added_points_indice.append(i);
                found = true;
                break;  // 找到后退出当前新增点的查找
            }
        }
        if (!found) {
            qWarning() << "新增点" << addedPoint << "在总采样点中未找到匹配项（可能精度问题）";
        }
    }

    // --------------------------
    // 3. 输出加载信息
    // --------------------------
    qDebug() << "成功加载自适应采样点:" << sampling_points.size() << "个点";
    qDebug() << "其中新增点数量:" << newly_added_points_indice.size() << "个";

    if (rootObj.contains("statistics")) {
        QJsonObject statsObj = rootObj["statistics"].toObject();
        if (statsObj.contains("position_range") && statsObj["position_range"].isArray()) {
            QJsonArray rangeArray = statsObj["position_range"].toArray();
            if (rangeArray.size() >= 2) {
                qDebug() << "位置范围:[" << rangeArray[0].toDouble()
                    << "," << rangeArray[1].toDouble() << "]";
            }
        } else {
            qWarning() << "JSON文件中缺少有效的 position_range 字段";
        }
    } else {
        qWarning() << "JSON文件中缺少 statistics 字段";
    }
}

void ModelSlicesProducer::generateSlicesLambda(const QVector<QPair<QPair<float, float>, Edge>>& preprocess_edges, float in_fix_stride, QVector<float> &out_strides)
{
    // 尝试加载自适应采样点
    // QVector<float> adaptive_points;
    // loadAdaptiveSamplingPoints("adaptive_sampling_result.json", adaptive_points, out_which_is_new);

    // if (!adaptive_points.isEmpty()) {
    //     // 使用自适应采样点
    //     out_strides = adaptive_points;
    //     qDebug() << "使用自适应采样点，数量:" << out_strides.size();
    // } else {
    //     // 回退到固定步长采样
    //     out_strides.clear();
    //     float current = m_lowest;
    //     while (current <= m_highest) {
    //         out_strides.append(current);
    //         current += in_fix_stride;
    //     }
    //     qDebug() << "使用固定步长采样，数量:" << out_strides.size();
    // }

    // // 确保采样点排序（自适应采样点可能不是严格有序的）
    // std::sort(out_strides.begin(), out_strides.end());

    // // 移除重复点（如果有的话）
    // auto last = std::unique(out_strides.begin(), out_strides.end());
    // out_strides.erase(last, out_strides.end());

    // qDebug() << "最终采样点数量:" << out_strides.size();
    // qDebug() << "采样范围:[" << out_strides.first() << "," << out_strides.last() << "]";

    //******************************************************************************************************

    // 防止程序崩溃，如果输入不合法则默认设置为0.01f切片
    if(in_fix_stride <= 0.0f)
        in_fix_stride = 0.01f;

    float totalHeight = m_highest - m_lowest;

    // 调整 stride，确保顶部和尾部都有切片
    int numSlices = static_cast<int>(std::ceil(totalHeight / in_fix_stride));
    float adjustedStride = totalHeight / numSlices;

    // 生成基础切片
    out_strides.clear();
    for (int i = 0; i <= numSlices; ++i)
    {
        float currentLambda = m_highest - i * adjustedStride;
        if (i == numSlices) currentLambda = m_lowest;
        out_strides.append(currentLambda);
    }

    //******************************************************************************************************

    // // 1. 统计每个区间内完全包含的边数量 E
    // QVector<int> edge_counts(out_strides.size() - 1, 0);

    // for(const auto& edge_info : preprocess_edges)
    // {
    //     float a = edge_info.first.first;  // 较大值
    //     float b = edge_info.first.second; // 较小值

    //     // 检查边是否完全包含在某个切片区间内
    //     for (int i = 0; i < out_strides.size() - 1; ++i)
    //     {
    //         // 如果边的区间 [b, a] 完全包含在切片区间 [interval_low, interval_high] 内
    //         if (b > out_strides[i+1] && a < out_strides[i])
    //         {
    //             edge_counts[i]++;
    //             break;
    //         }
    //     }
    // }

    // // 2. 对每个区间根据 E 值计算需要插入的切片数量 Y
    // QVector<int> insert_counts(out_strides.size() - 1, 0);
    // for (int i = 0; i < edge_counts.size(); ++i)
    // {
    //     insert_counts[i] = calculateInsertCount(edge_counts[i]);
    // }

    // // 3. 根据插入数量实际更改 out_strides
    // insertSlicesBasedOnCounts(out_strides, insert_counts, in_fix_stride);

    // qDebug() << "Generated" << out_strides.size() << "slices";
}

QVector<Edge> binarySiftPartitions(const QVector<QPair<QPair<float, float>, Edge>>& preprocess_edges, float lambda)
{
    QVector<Edge> result;

    // 如果预处理数组为空，直接返回空结果
    if (preprocess_edges.isEmpty())
        return result;

    // 二分查找最后一个满足 a_i >= lambda 的位置
    int left = 0;
    int right = preprocess_edges.size() - 1;
    int lastValidIndex = -1;

    while (left <= right)
    {
        int mid = left + (right - left) / 2;
        if (preprocess_edges[mid].first.first >= lambda)
        {
            lastValidIndex = mid; // 记录可能的位置
            left = mid + 1;       // 继续向右查找更大的索引
        }
        else
            right = mid - 1;      // 向左查找
    }

    // 如果没有找到满足条件的区间，直接返回空结果
    if (lastValidIndex == -1)
        return result;

    // 遍历从 0 到 lastValidIndex 的区间，筛选出 b_i <= lambda 的边
    for (int i = 0; i <= lastValidIndex; ++i) {
        const auto& partition = preprocess_edges[i];
        float b_i = partition.first.second;

        if (b_i <= lambda) {
            result.append(partition.second);
        }
    }

    return result;
}

QVector<Vertex> intersectEdgesWithPlane(const QVector<Edge> &sifted_edges, const QVector3D &direction_norm, float lambda)
{
    QVector<Vertex> intersections;

    // 平面上的点 P0 = lambda * direction_norm
    QVector3D P0 = lambda * direction_norm;

    for (const Edge& edge : sifted_edges)
    {
        const QVector3D& v1 = edge.v1.pos;
        const QVector3D& v2 = edge.v2.pos;

        // 边的方向向量
        QVector3D edgeDirection = v2 - v1;

        // 计算分母：direction_norm · edgeDirection
        float denominator = QVector3D::dotProduct(direction_norm, edgeDirection);

        // 如果分母为 0，说明边与平面平行，没有交点
        if (qFuzzyIsNull(denominator)) {
            continue;
        }

        // 计算参数 t
        float t = QVector3D::dotProduct(direction_norm, P0 - v1) / denominator;

        // 如果 t 在 [0, 1] 范围内，说明交点在边上
        if (t >= 0.0f && t <= 1.0f)
        {
            // 计算交点坐标
            Vertex intersection;
            intersection.pos = v1 + t * edgeDirection;
            intersection.norm = edge.norm;
            // 插值计算颜色
            intersection.color = QVector4D(
                edge.v1.color.x() * (1 - t) + edge.v2.color.x() * t,
                edge.v1.color.y() * (1 - t) + edge.v2.color.y() * t,
                edge.v1.color.z() * (1 - t) + edge.v2.color.z() * t,
                edge.v1.color.w() * (1 - t) + edge.v2.color.w() * t
            );

            intersections.append(intersection);
        }
    }

    return intersections;
}

// 切面法向量以及切片间隔需要配置文件提供
void ModelSlicesProducer::generateShownVertices(const QVector<QPair<QPair<float, float>, Edge>> &preprocessed_partitions, const QVector3D& slice_norm, float stride,
                                                   QVector<Vertex>& out_intersected_points, QVector<qsizetype>& out_intersected_points_counts, QVector<float>& out_slice_lambdas)
{
    // 防止程序崩溃，如果输入不合法则默认设置为0.01f切片
    if(stride <= 0.0f)
        stride = 0.01f;

    float totalHeight = m_highest - m_lowest;
    int numSlices = static_cast<int>(std::ceil(totalHeight / stride)); // 向上取整，确保覆盖整个范围

    // 调整 stride，确保顶部和尾部都有切片
    float adjustedStride = totalHeight / numSlices;

    // 按 adjustedStride 切片
    for (int i = 0; i <= numSlices; ++i)
    {
        float currentLambda = m_highest - i * adjustedStride;

        // 确保最后一个切片是 m_lowest
        if (i == numSlices)
            currentLambda = m_lowest;

        // 二分筛边
        QVector<Edge> sifted_edges = binarySiftPartitions(preprocessed_partitions, currentLambda);

        // 计算当前切片的交点
        auto intersections = intersectEdgesWithPlane(sifted_edges, slice_norm, currentLambda);

        // 追加模型切片
        out_intersected_points.append(intersections);

        // 记录当前交点的数量
        out_intersected_points_counts.append(intersections.size());

        // 记录当前切片用的高度
        out_slice_lambdas.append(currentLambda);
    }
}
